/*
 * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include "esp32_i2c.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include <vector>
#include <memory>

static const char* TAG = "I2C_EXAMPLE";

// MPU9250传感器地址和寄存器
#define MPU9250_SENSOR_ADDR         0x68
#define MPU9250_WHO_AM_I_REG_ADDR   0x75
#define MPU9250_PWR_MGMT_1_REG_ADDR 0x6B
#define MPU9250_RESET_BIT           7

void i2c_basic_example() {
    ESP_LOGI(TAG, "=== I2C基础使用示例 ===");
    
    // 创建I2C实例
    I2cMaster i2c;
    
    // 配置I2C
    I2CConfig config;
    config.type = I2CType::HARDWARE;
    config.i2c_port = 0;
    config.scl_io_num = GPIO_NUM_22;  // 根据实际硬件修改
    config.sda_io_num = GPIO_NUM_21;  // 根据实际硬件修改
    config.scl_speed_hz = 100000;     // 100kHz
    config.enable_internal_pullup = true;
    
    // 初始化I2C
    esp_err_t ret = i2c.init(config);
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "I2C初始化失败: %s", I2cMaster::errorToString(ret));
        return;
    }
    
    ESP_LOGI(TAG, "I2C初始化成功");
    
    // 扫描总线上的设备
    std::vector<uint8_t> found_devices;
    ret = i2c.scanBus(found_devices);
    if (ret == ESP_OK) {
        ESP_LOGI(TAG, "扫描到 %zu 个设备", found_devices.size());
        for (uint8_t addr : found_devices) {
            ESP_LOGI(TAG, "设备地址: 0x%02X", addr);
        }
    }
    
    // 检查MPU9250是否存在
    if (i2c.probeDevice(MPU9250_SENSOR_ADDR)) {
        ESP_LOGI(TAG, "找到MPU9250传感器");
        
        // 读取WHO_AM_I寄存器
        uint8_t who_am_i;
        ret = i2c.readRegister(MPU9250_SENSOR_ADDR, MPU9250_WHO_AM_I_REG_ADDR, who_am_i);
        if (ret == ESP_OK) {
            ESP_LOGI(TAG, "WHO_AM_I = 0x%02X", who_am_i);
        } else {
            ESP_LOGE(TAG, "读取WHO_AM_I失败: %s", I2cMaster::errorToString(ret));
        }
        
        // 写入电源管理寄存器（复位设备）
        ret = i2c.writeRegister(MPU9250_SENSOR_ADDR, MPU9250_PWR_MGMT_1_REG_ADDR, 1 << MPU9250_RESET_BIT);
        if (ret == ESP_OK) {
            ESP_LOGI(TAG, "MPU9250复位成功");
        } else {
            ESP_LOGE(TAG, "MPU9250复位失败: %s", I2cMaster::errorToString(ret));
        }
    } else {
        ESP_LOGW(TAG, "未找到MPU9250传感器");
    }
}

void i2c_optimized_example() {
    ESP_LOGI(TAG, "=== I2C性能优化示例 ===");
    
    // 创建I2C实例
    I2cMaster i2c;
    
    // 配置I2C
    I2CConfig config;
    config.type = I2CType::HARDWARE;
    config.i2c_port = 0;
    config.scl_io_num = GPIO_NUM_22;
    config.sda_io_num = GPIO_NUM_21;
    config.scl_speed_hz = 400000;     // 400kHz高速模式
    config.enable_internal_pullup = true;
    
    // 初始化I2C
    esp_err_t ret = i2c.init(config);
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "I2C初始化失败: %s", I2cMaster::errorToString(ret));
        return;
    }
    
    // 预先添加设备（性能优化）
    i2c_master_dev_handle_t mpu9250_handle = i2c.addDevice(MPU9250_SENSOR_ADDR, 400000);
    if (mpu9250_handle == nullptr) {
        ESP_LOGE(TAG, "添加MPU9250设备失败");
        return;
    }
    
    ESP_LOGI(TAG, "MPU9250设备添加成功");
    
    // 使用设备句柄进行高效传输
    uint8_t who_am_i;
    ret = i2c.readRegister(mpu9250_handle, MPU9250_WHO_AM_I_REG_ADDR, who_am_i);
    if (ret == ESP_OK) {
        ESP_LOGI(TAG, "使用设备句柄读取WHO_AM_I = 0x%02X", who_am_i);
    }
    
    // 批量读取多个寄存器
    uint8_t reg_data[6];
    ret = i2c.readRegister(mpu9250_handle, 0x3B, reg_data, sizeof(reg_data));  // 读取加速度计数据
    if (ret == ESP_OK) {
        ESP_LOGI(TAG, "批量读取成功，数据: %02X %02X %02X %02X %02X %02X", 
                reg_data[0], reg_data[1], reg_data[2], reg_data[3], reg_data[4], reg_data[5]);
    }
    
    // 性能测试：连续读取1000次
    uint32_t start_time = xTaskGetTickCount();
    for (int i = 0; i < 1000; i++) {
        i2c.readRegister(mpu9250_handle, MPU9250_WHO_AM_I_REG_ADDR, who_am_i);
    }
    uint32_t end_time = xTaskGetTickCount();
    uint32_t duration_ms = (end_time - start_time) * portTICK_PERIOD_MS;
    
    ESP_LOGI(TAG, "1000次读取耗时: %lu ms, 平均每次: %.2f ms", 
            duration_ms, (float)duration_ms / 1000.0f);
    
    // 移除设备（可选，析构函数会自动清理）
    ret = i2c.removeDevice(mpu9250_handle);
    if (ret == ESP_OK) {
        ESP_LOGI(TAG, "设备移除成功");
    }
}

void i2c_software_example() {
    ESP_LOGI(TAG, "=== 软件I2C示例 ===");
    
#if CONFIG_ESP32_I2C_ENABLE_SOFTWARE_I2C
    // 创建I2C实例
    I2cMaster i2c;
    
    // 配置软件I2C
    I2CConfig config;
    config.type = I2CType::SOFTWARE;
    config.i2c_port = 1;  // 软件I2C可以使用任意端口号
    config.scl_io_num = GPIO_NUM_18;
    config.sda_io_num = GPIO_NUM_19;
    config.scl_speed_hz = 100000;     // 软件I2C建议使用较低频率
    config.enable_internal_pullup = true;
    
    // 初始化软件I2C
    esp_err_t ret = i2c.init(config);
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "软件I2C初始化失败: %s", I2cMaster::errorToString(ret));
        return;
    }
    
    ESP_LOGI(TAG, "软件I2C初始化成功");
    
    // 扫描设备
    std::vector<uint8_t> found_devices;
    ret = i2c.scanBus(found_devices, 50);  // 软件I2C使用较短超时
    if (ret == ESP_OK) {
        ESP_LOGI(TAG, "软件I2C扫描到 %zu 个设备", found_devices.size());
    }
    
    // 测试基本通信
    if (i2c.probeDevice(MPU9250_SENSOR_ADDR, 100)) {
        ESP_LOGI(TAG, "软件I2C找到MPU9250");
        
        uint8_t who_am_i;
        ret = i2c.readRegister(MPU9250_SENSOR_ADDR, MPU9250_WHO_AM_I_REG_ADDR, who_am_i, 100);
        if (ret == ESP_OK) {
            ESP_LOGI(TAG, "软件I2C读取WHO_AM_I = 0x%02X", who_am_i);
        }
    }
#else
    ESP_LOGW(TAG, "软件I2C未启用，请在配置中启用CONFIG_ESP32_I2C_ENABLE_SOFTWARE_I2C");
#endif
}

extern "C" void app_main() {
    ESP_LOGI(TAG, "ESP32 I2C示例开始");
    
    // 基础使用示例
    i2c_basic_example();
    vTaskDelay(pdMS_TO_TICKS(1000));
    
    // 性能优化示例
    i2c_optimized_example();
    vTaskDelay(pdMS_TO_TICKS(1000));
    
    // 软件I2C示例
    i2c_software_example();
    
    ESP_LOGI(TAG, "所有示例完成");
}